#include "global_vars.h"

struct event *timeout1, *timeout2, *socketEve1;
struct timeval tv1, tv2, performance_end_time, performance_start_time, start_time, end_time;
int vector_clock[MAX_RING_NODES], submit_per_wake;
struct rbtree *myTree;
msg *head;
int self_id, num_proposers;
//------------------------------------------------------------------------------------------------
void enable_signal_handler();
void clean_exit(int sig);
void terminate();
void enable_signal_handler();
void enable_signal_handler();
void validate_input_parameters(int argc, char **argv);
void initialize_buffers();
void initialize_events();
void add_common_events();
void initialize();

int main(int argc, char ** argv) {
	char am_i_proposer;
	int status;

	enable_signal_handler();
	validate_input_parameters(argc, argv);
	parse_config_file(self_id, config_file, 0, num_proposers);
	status = recv(get_config_info()->nodes[get_config_info()->self_id].leader_sid, &am_i_proposer, sizeof(char), MSG_WAITALL);
	assert(status == sizeof(char));
	printf("AM_I_PROPOSER: %c\n", am_i_proposer);
	close(get_config_info()->nodes[get_config_info()->self_id].leader_sid);
	initialize_buffers();
	initialize_events();
	event_init();
	add_common_events();
	printf("=======================================================\n");
	//--------------------------------------------------------------------------
	if (am_i_proposer == 'y') { //Receving yes from the leader means this process is a sender.

		evtimer_set(timeout1, utoBroadcast, timeout1);
		status = evtimer_add(timeout1, &tv1);
		assert(status >= 0);
		//		event_set(timeout1, get_config_info()->nodes[self_id].successor_sid, EV_WRITE | EV_PERSIST, utoBroadcast, NULL);
		//		status = event_add(timeout1, NULL);
		//		assert(status >= 0);

	}
	event_dispatch();
	terminate();
	exit(0);
}
void add_common_events() {
	int status;

	if (get_config_info()->num_proposers > 0) {
		event_set(socketEve1, get_config_info()->nodes[get_config_info()->self_id].self_sid, EV_READ | EV_PERSIST, message_processor, NULL);
		status = event_add(socketEve1, NULL);
		assert(status >= 0);
	}

	evtimer_set(timeout2, compute_performance, timeout2);
	status = evtimer_add(timeout2, &tv2);
	assert(status >= 0);

	gettimeofday(&start_time, NULL);
	gettimeofday(&performance_start_time, NULL);

}
void terminate() {
	store_performance_in_file(performance_file, latency_file, sd_avg_file, performance_index);
	close(get_config_info()->nodes[self_id].successor_sid);
	close(get_config_info()->nodes[self_id].successor_sid);
	close(get_config_info()->nodes[self_id].leader_sid);
	rbdestroy(myTree);

}
void clean_exit(int sig) {

	signal(sig, clean_exit);
	terminate();
	exit(0);

}
void enable_signal_handler() {
	signal(SIGINT, clean_exit);
	signal(SIGKILL, clean_exit);
	signal(SIGABRT, clean_exit);
	signal(SIGALRM, clean_exit);
	signal(SIGBUS, clean_exit);
	signal(SIGCHLD, clean_exit);
	signal(SIGCONT, clean_exit);
	signal(SIGFPE, clean_exit);
	signal(SIGHUP, clean_exit);
	signal(SIGILL, clean_exit);
	signal(SIGPIPE, clean_exit);
	signal(SIGQUIT, clean_exit);
	signal(SIGSEGV, clean_exit);
	signal(SIGSTOP, clean_exit);
	signal(SIGTERM, clean_exit);
	signal(SIGTSTP, clean_exit);
	signal(SIGTTIN, clean_exit);
	signal(SIGTTOU, clean_exit);
	signal(SIGUSR1, clean_exit);
	signal(SIGUSR2, clean_exit);
	signal(SIGPROF, clean_exit);
	signal(SIGSYS, clean_exit);
	signal(SIGTRAP, clean_exit);
	signal(SIGURG, clean_exit);
	signal(SIGVTALRM, clean_exit);
	signal(SIGXCPU, clean_exit);
	signal(SIGXFSZ, clean_exit);

}
void validate_input_parameters(int argc, char **argv) {
	if (argc != 8) {
		printf("Incompatible call to this function. Try Again.!\n");
		printf("<1. Process ID>\n"
			"<2. Num of Packets per interval>\n"
			"<3. Interval (MicroSeconds)>\n"
			"<4. Performance File>\n"
			"<5. Configuration File>\n"
			"<6. Number of Proposers>\n"
			"<7. Latency File\n>");
		exit(1);
	} else {

		self_id = atoi(argv[1]);
		submit_per_wake = atoi(argv[2]);
		tv1.tv_usec = atoi(argv[3]); //tv1, is the time structure used to trigger utoBroadcast method
		performance_file = argv[4];
		config_file = argv[5];
		num_proposers = atoi(argv[6]);
		latency_file = argv[7];
	}
}

void initialize_buffers() {

	interval_performance = (performance*) malloc(sizeof(performance));
	nulify_performance(interval_performance);

	int i;
	for (i = 0; i < MAX_RING_NODES; i++)
		vector_clock[i] = 0;

	myTree = rbinit(compare, NULL);

	tv1.tv_sec = 0;
	tv2.tv_usec = 0;
	tv2.tv_sec = 1;

}
void initialize_events() {
	socketEve1 = (struct event*) malloc(sizeof(struct event));
	timeout1 = (struct event*) malloc(sizeof(struct event));
	timeout2 = (struct event*) malloc(sizeof(struct event));

}

